# 坐标结构
mutable struct FCPoint
    x::Float64  # 横坐标
    y::Float64  # 纵坐标
    function FCPoint(ix::Float64, iy::Float64)
        p = new()
        p.x = ix
        p.y = iy
        return p
    end
end

# 大小结构
mutable struct FCSize
    cx::Float64  # 长
    cy::Float64  # 宽
    function FCSize(icx::Float64, icy::Float64)
        s = new()
        s.cx = icx
        s.cy = icy
        return s
    end
end

# 矩形结构
mutable struct FCRect
    left::Float64
    top::Float64
    right::Float64
    bottom::Float64
    function FCRect(ileft::Float64, itop::Float64, iright::Float64, ibottom::Float64)
        r = new()
        r.left = ileft
        r.top = itop
        r.right = iright
        r.bottom = ibottom
        return r
    end
end

# 边距信息
mutable struct FCPadding
    left::Float64
    top::Float64
    right::Float64
    bottom::Float64
    function FCPadding(ileft::Float64, itop::Float64, iright::Float64, ibottom::Float64)
        pad = new()
        pad.left = ileft
        pad.top = itop
        pad.right = iright
        pad.bottom = ibottom
        return pad
    end
end

# 绘图
mutable struct FCPaint
    cancelClick::Bool
    defaultUIStyle::String
    dragBeginPoint::FCPoint
    dragBeginRect::FCRect
    draggingView::Union{FCView,Nothing}
    editMode::Int
    editingTextBox::Union{FCView,Nothing}
    firstTouch::Bool
    focusedView::Union{FCView,Nothing}
    isDoubleClick::Bool
    isMobile::Bool
    isPath::Bool
    lastClickTime::Int
    moveTo::Bool
    offsetX::Float64
    offsetY::Float64
    ratio::Float64
    resizeColumnState::Float64
    resizeColumnBeginWidth::Float64
    resizeColumnIndex::Int
    scaleFactorX::Float64
    scaleFactorY::Float64
    secondTouch::Bool
    systemFont::String
    touchDownPoint::FCPoint
    touchFirstPoint::FCPoint
    touchSecondPoint::FCPoint
    touchDownView::Union{FCView,Nothing}
    touchMoveView::Union{FCView,Nothing}
    views::Array{FCView,1}

    function FCPaint()
        paint = new()
        paint.cancelClick = false
        paint.defaultUIStyle = "light"
        paint.dragBeginPoint = FCPoint(0.0, 0.0)
        paint.dragBeginRect = FCRect(0.0, 0.0, 0.0, 0.0)
        paint.draggingView = nothing
        paint.editMode = 1
        paint.editingTextBox = nothing
        paint.firstTouch = false
        paint.focusedView = nothing
        paint.isDoubleClick = false
        paint.isMobile = false
        paint.isPath = false
        paint.lastClickTime = 0
        paint.moveTo = false
        paint.offsetX = 0.0
        paint.offsetY = 0.0
        paint.ratio = 1.0
        paint.resizeColumnState = 0.0
        paint.resizeColumnBeginWidth = 0.0
        paint.resizeColumnIndex = -1
        paint.scaleFactorX = 1.0
        paint.scaleFactorY = 1.0
        paint.secondTouch = false
        paint.systemFont = "Arial"
        paint.touchDownPoint = FCPoint(0.0, 0.0)
        paint.touchFirstPoint = FCPoint(0.0, 0.0)
        paint.touchSecondPoint = FCPoint(0.0, 0.0)
        paint.touchDownView = nothing
        paint.touchMoveView = nothing
        paint.views = []
        return paint
    end
end

function (paint::FCPaint)(x1::Float64, y1::Float64, x2::Float64, y2::Float64)
end

function (paint::FCPaint)()
end

function (paint::FCPaint)(rect::FCRect)
end

function (paint::FCPaint)()
end

function (paint::FCPaint)()
end

function (paint::FCPaint)(color::String, width::Float64, style::Array{Int,1}, x1::Float64, y1::Float64, x2::Float64, y2::Float64)
end

function (paint::FCPaint)(color::String, width::Float64, style::Array{Int,1})
end

function (paint::FCPaint)(color::String, width::Float64, style::Array{Int,1}, apt::Array{FCPoint,1})
end

function (paint::FCPaint)(color::String, width::Float64, style::Array{Int,1}, apt::Array{FCPoint,1})
end

function (paint::FCPaint)(image::Any, left::Float64, top::Float64, right::Float64, bottom::Float64)
end

function (paint::FCPaint)(color::String, width::Float64, style::Array{Int,1}, left::Float64, top::Float64, right::Float64, bottom::Float64)
end

function (paint::FCPaint)(color::String, width::Float64, style::Array{Int,1}, left::Float64, top::Float64, right::Float64, bottom::Float64)
end

function (paint::FCPaint)(color::String, width::Float64, style::Array{Int,1}, left::Float64, top::Float64, right::Float64, bottom::Float64, cornerRadius::Float64)
end

function (paint::FCPaint)(text::String, color::String, font::String, x::Float64, y::Float64)
end

function (paint::FCPaint)()
end

function (paint::FCPaint)(color::String)
end

function (paint::FCPaint)(color::String, apt::Array{FCPoint,1})
end

function (paint::FCPaint)(color::String, left::Float64, top::Float64, right::Float64, bottom::Float64)
end

function (paint::FCPaint)(color::String, left::Float64, top::Float64, right::Float64, bottom::Float64, cornerRadius::Float64)
end

function (paint::FCPaint)(color::String, left::Float64, top::Float64, right::Float64, bottom::Float64)
end

function (paint::FCPaint)(left::Float64, top::Float64, right::Float64, bottom::Float64)
end

function (paint::FCPaint)(x::Float64, y::Float64)
    paint.offsetX = x
    paint.offsetY = y
end

function (paint::FCPaint)(text::String, font::String)::FCSize
    return FCSize(0.0, 0.0)
end

function (paint::FCPaint)()
end

function (paint::FCPaint)()
end

function (paint::FCPaint)(text::String, color::String, font::String, left::Float64, top::Float64, right::Float64, bottom::Float64)
    if text!= ""
        tSize = paint(text, font)
        if tSize.cx < right - left
            paint(text, color, font, left, top)
        else
            if tSize.cx > 0
                subLen = 3
                while true
                    newLen = length(text) - subLen
                    if newLen > 0
                        newText = text[1:newLen] * "..."
                        tSize = paint(newText, font)
                        if tSize.cx < right - left
                            paint(newText, color, font, left, top)
                            break
                        else
                            subLen += 3
                        end
                    else
                        break
                    end
                end
            end
        end
    end
end

# 基础视图
mutable struct FCView
    allowDrag::Bool
    allowResize::Bool
    align::String
    allowDragScroll::Bool
    allowPreviewsEvent::Bool
    backColor::String
    borderColor::String
    borderWidth::Float64
    clipRect::FCRect
    cornerRadius::Float64
    cursor::String
    downScrollHButton::Bool
    downScrollVButton::Bool
    displayOffset::Bool
    dock::String
    enabled::Bool
    font::String
    hoveredColor::Union{String,Nothing}
    hoverScrollHButton::Bool
    hoverScrollVButton::Bool
    hScrollIsVisible::Bool
    location::FCPoint
    margin::FCPadding
    maximumSize::FCSize
    padding::FCPadding
    paint::Union{FCPaint,Nothing}
    parent::Union{FCView,Nothing}
    pushedColor::String
    resizePoint::Int
    scrollV::Float64
    scrollH::Float64
    scrollSize::Float64
    showHScrollBar::Bool
    showVScrollBar::Bool
    scrollBarColor::String
    scrollBarHoveredColor::String
    size::FCSize
    startScrollH::Float64
    startScrollV::Float64
    startPoint::FCPoint
    startRect::FCRect
    tabIndex::Int
    tabStop::Bool
    text::String
    textColor::String
    textAlign::String
    topMost::Bool
    touchDownTime::Int
    viewName::String
    visible::Bool
    verticalAlign::String
    viewType::String
    vScrollIsVisible::Bool
    views::Array{FCView,1}

    function FCView()
        view = new()
        view.allowDrag = false
        view.allowResize = false
        view.align = "left"
        view.allowDragScroll = true
        view.allowPreviewsEvent = false
        view.backColor = "rgb(255,255,255)"
        view.borderColor = "rgb(150,150,150)"
        view.borderWidth = 1.0
        view.clipRect = FCRect(0.0, 0.0, 0.0, 0.0)
        view.cornerRadius = 0.0
        view.cursor = ""
        view.downScrollHButton = false
        view.downScrollVButton = false
        view.displayOffset = true
        view.dock = "none"
        view.enabled = true
        view.font = "Default,12"
        view.hoveredColor = nothing
        view.hoverScrollHButton = false
        view.hoverScrollVButton = false
        view.hScrollIsVisible = false
        view.location = FCPoint(0.0, 0.0)
        view.margin = FCPadding(0.0, 0.0, 0.0, 0.0)
        view.maximumSize = FCSize(0.0, 0.0)
        view.padding = FCPadding(0.0, 0.0, 0.0, 0.0)
        view.paint = nothing
        view.parent = nothing
        view.pushedColor = "rgb(100,100,100)"
        view.resizePoint = -1
        view.scrollV = 0.0
        view.scrollH = 0.0
        view.scrollSize = 8.0
        view.showHScrollBar = false
        view.showVScrollBar = false
        view.scrollBarColor = "rgb(200,200,200)"
        view.scrollBarHoveredColor = "rgb(42,138,195)"
        view.size = FCSize(0.0, 0.0)
        view.startScrollH = 0.0
        view.startScrollV = 0.0
        view.startPoint = FCPoint(0.0, 0.0)
        view.startRect = FCRect(0.0, 0.0, 0.0, 0.0)
        view.tabIndex = 0
        view.tabStop = false
        view.text = ""
        view.textColor = "rgb(0,0,0)"
        view.textAlign = "left"
        view.topMost = false
        view.touchDownTime = 0
        view.viewName = ""
        view.visible = true
        view.verticalAlign = "top"
        view.viewType = "none"
        view.vScrollIsVisible = false
        view.views = []
        return view
    end
end

# 添加顶层视图
function addView(view::FCView, paint::FCPaint)
    view.paint = paint
    push!(paint.views, view)
end

# 添加到父视图
function addViewToParent(view::FCView, parent::FCView)
    view.paint = parent.paint
    if isempty(parent.views)
        parent.views = []
    end
    push!(parent.views, view)
    view.parent = parent
end

# 清除视图
function clearViews(paint::FCPaint)
    paint.views = []
end

# 移除顶层视图
function removeView(view::FCView, paint::FCPaint)
    if!isempty(paint.views)
        for i in eachindex(paint.views)
            if paint.views[i] == view
                deleteat!(paint.views, i)
                remove_views = [view]
                break
            end
        end
    end
end

# 从父视图中移除
function removeViewFromParent(view::FCView, parent::FCView)
    if!isempty(parent.views)
        for i in eachindex(parent.views)
            if parent.views[i] == view
                deleteat!(parent.views, i)
                remove_views = [view]
                break
            end
        end
    end
end

# 获取绝对位置X
function clientX(view::FCView)::Float64
    if view!== nothing
        cLeft = view.location.x
        if view.parent!== nothing
            if view.parent.displayOffset && view.parent.scrollH > 0
                return cLeft + clientX(view.parent) - view.parent.scrollH
            else
                return cLeft + clientX(view.parent)
            end
        else
            return cLeft
        end
    else
        return 0.0
    end
end

# 获取绝对位置Y
function clientY(view::FCView)::Float64
    if view!== nothing
        cTop = view.location.y
        if view.parent!== nothing
            if view.parent.displayOffset && view.parent.scrollV > 0
                return cTop + clientY(view.parent) - view.parent.scrollV
            else
                return cTop + clientY(view.parent)
            end
        else
            return cTop
        end
    else
        return 0.0
    end
end

# 是否包含坐标
function containsPoint(view::FCView, mp::FCPoint)::Bool
    if isViewEnabled(view)
        clx = clientX(view)
        cly = clientY(view)
        size = view.size
        cp = FCPoint(mp.x - clx, mp.y - cly)
        return (cp.x >= 0 && cp.x <= size.cx && cp.y >= 0 && cp.y <= size.cy)
    else
        return false
    end
end

# 查找有预处理事件的父视图
function findPreviewsEventParent(view::FCView)::Union{FCView,Nothing}
    if!view.allowPreviewsEvent && view.parent!== nothing
        if view.parent.allowPreviewsEvent
            return view.parent
        else
            return findPreviewsEventParent(view.parent)
        end
    else
        return nothing
    end
end

# 根据名称查找视图
function findViewByName(name::String, views::Array{FCView,1})::Union{FCView,Nothing}
    size = length(views)
    for i in 1:size
        view = views[i]
        if view.viewName == name
            return view
        else
            if!isempty(view.views)
                subView = findViewByName(name, view.views)
                if subView!== nothing
                    return subView
                end
            end
        end
    end
    return nothing
end

# 视图是否可用
function isViewEnabled(view::FCView)::Bool
    return view.enabled
end

# 根据坐标查找视图
function findView(mp::FCPoint, views::Array{FCView,1})::Union{FCView,Nothing}
    size = length(views)
    for i in size:-1:1
        view = views[i]
        if view.visible && view.topMost
            hasPoint = containsPoint(view, mp)
            if hasPoint
                if view.vScrollIsVisible && view.scrollSize > 0
                    clx = clientX(view)
                    if mp.x >= clx + view.size.cx - view.scrollSize
                        return view
                    end
                end
                if view.hScrollIsVisible && view.scrollSize > 0
                    cly = clientY(view)
                    if mp.y >= cly + view.size.cy - view.scrollSize
                        return view
                    end
                end
                if!isempty(view.views)
                    subView = findView(mp, view.views)
                    if subView!== nothing
                        return subView
                    end
                end
                return view
            end
        end
    end
    for i in size:-1:1
        view = views[i]
        if view.visible &&!view.topMost
            hasPoint = containsPoint(view, mp)
            if hasPoint
                if view.vScrollIsVisible && view.scrollSize > 0
                    clx = clientX(view)
                    if mp.x >= clx + view.size.cx - view.scrollSize
                        return view
                    end
                end
                if view.hScrollIsVisible && view.scrollSize > 0
                    cly = clientY(view)
                    if mp.y >= cly + view.size.cy - view.scrollSize
                        return view
                    end
                end
                if!isempty(view.views)
                    subView = findView(mp, view.views)
                    if subView!== nothing
                        return subView
                    end
                end
                return view
            end
        end
    end
    return nothing
end

# 是否重绘时可见
function isPaintVisible(view::FCView)::Bool
    if view.visible
        if view.parent!== nothing
            if view.parent.visible
                return isPaintVisible(view.parent)
            else
                return false
            end
        else
            return true
        end
    else
        return false
    end
end

# 是否重绘时可见
function isViewEnabled(view::FCView)::Bool
    if view.enabled
        if view.parent!== nothing
            if view.parent.enabled
                return isViewEnabled(view.parent)
            else
                return false
            end
        else
            return true
        end
    else
        return false
    end
end

# 获取区域的交集
function getIntersectRect(lpDestRect::FCRect, lpSrc1Rect::FCRect, lpSrc2Rect::FCRect)::Int
    lpDestRect.left = max(lpSrc1Rect.left, lpSrc2Rect.left)
    lpDestRect.right = min(lpSrc1Rect.right, lpSrc2Rect.right)
    lpDestRect.top = max(lpSrc1Rect.top, lpSrc2Rect.top)
    lpDestRect.bottom = min(lpSrc1Rect.bottom, lpSrc2Rect.bottom)
    if lpDestRect.right > lpDestRect.left && lpDestRect.bottom > lpDestRect.top
        return 1
    else
        lpDestRect.left = 0
        lpDestRect.right = 0
        lpDestRect.top = 0
        lpDestRect.bottom = 0
        return 0
    end
end

# 重绘视图
function renderViews(views::Array{FCView,1}, paint::FCPaint, rect::Union{FCRect,Nothing})
    viewsSize = length(views)
    for i in 1:viewsSize
        view = views[i]
        if rect === nothing
            if!isempty(view.views)
                subViewsSize = length(view.views)
                if subViewsSize > 0
                    renderViews(view.views, paint, nothing)
                end
            end
            view.clipRect = nothing
            continue
        end
        if!view.topMost && isPaintVisible(view)
            clx = clientX(view)
            cly = clientY(view)
            drawRect = FCRect(0, 0, view.size.cx, view.size.cy)
            clipRect = FCRect(clx, cly, clx + view.size.cx, cly + view.size.cy)
            destRect = FCRect(0, 0, 0, 0)
            if getIntersectRect(destRect, rect, clipRect) > 0
                paint.save()
                paint.setOffset(0, 0)
                paint.setClip(destRect.left, destRect.top, destRect.right, destRect.bottom)
                view.clipRect = destRect
                paint.setOffset(clx, cly)
                if!isempty(view.views)
                    subViewsSize = length(view.views)
                    if subViewsSize > 0
                        renderViews(view.views, paint, destRect)
                    end
                end
                paint.setOffset(clx, cly)
                paint.restore()
            else
                if!isempty(view.views)
                    subViewsSize = length(view.views)
                    if subViewsSize > 0
                        renderViews(view.views, paint, nothing)
                    end
                end
                view.clipRect = nothing
            end
        end
    end
    for i in 1:viewsSize
        view = views[i]
        if rect === nothing
            continue
        end
        if view.topMost && isPaintVisible(view)
            clx = clientX(view)
            cly = clientY(view)
            drawRect = FCRect(0, 0, view.size.cx, view.size.cy)
            clipRect = FCRect(clx, cly, clx + view.size.cx, cly + view.size.cy)
            destRect = FCRect(0, 0, 0, 0)
            if getIntersectRect(destRect, rect, clipRect) > 0
                paint.save()
                paint.setOffset(0, 0)
                view.clipRect = destRect
                paint.setClip(destRect.left, destRect.top, destRect.right, destRect.bottom)
                paint.setOffset(clx, cly)
                if!isempty(view.views)
                    subViewsSize = length(view.views)
                    if subViewsSize > 0
                        renderViews(view.views, paint, destRect)
                    end
                end
                paint.setOffset(clx, cly)
                paint.restore()
            else
                if!isempty(view.views)
                    subViewsSize = length(view.views)
                    if subViewsSize > 0
                        renderViews(view.views, paint, nothing)
                    end
                end
                view.clipRect = nothing
            end
        end
    end
end

# 全局刷新
function invalidate(paint::FCPaint)
end

# 刷新视图
function invalidateView(view::FCView)
end